package mx.com.crowdgine.particlesystem.jogl;

import javax.media.opengl.GLAutoDrawable;

import com.jogamp.common.nio.Buffers;
import com.jogamp.opencl.gl.CLGLBuffer;

import mx.com.crowdgine.particlesystem.ParticleSystem;
import mx.com.crowdgine.util.gpucompute.jocl.JoclGpuCompute;

public class SineWaveParticleSystem implements ParticleSystem {
	
	private JoclGpuCompute gpuComputeObj;
	
	private boolean initialized = false;
	
	public static final String VERTICES_NAME = "VERTICES";
	
	private final int MESH_SIZE = 256; 
	private final int VERTICES_SIZE = Buffers.SIZEOF_FLOAT * 4 * MESH_SIZE * MESH_SIZE;
	
	private final String KERNEL_FILE = "SineWave.cl";
	private final String KERNEL_NAME = "sineWave";
	
	public void init(Object drawableImplementation) {
		if(drawableImplementation instanceof GLAutoDrawable) {
			gpuComputeObj = new JoclGpuCompute((GLAutoDrawable) drawableImplementation);
			gpuComputeObj.initCL(this.getClass().getResourceAsStream(KERNEL_FILE));
			
			//Create vertices buffer with OGL interoperability
			gpuComputeObj.createCLGLBuffer((GLAutoDrawable) drawableImplementation, VERTICES_NAME, VERTICES_SIZE, CLGLBuffer.Mem.WRITE_ONLY);
			
			//Assign Kernel arguments
			gpuComputeObj.setKernelArgs(KERNEL_NAME, gpuComputeObj.clGLBuffers.get(VERTICES_NAME));
			gpuComputeObj.setKernelArg(KERNEL_NAME, 1, MESH_SIZE);
			gpuComputeObj.setKernelArg(KERNEL_NAME, 2, 0.0f);
			this.initialized = true;
		} else {
			throw new UnsupportedOperationException("Drawable implementation " + drawableImplementation + " not currently supported by SineWaveParticleSystem.");
		}
	}
	
	@Override
	public void simulate(float time) {
		gpuComputeObj.setKernelArg(KERNEL_NAME, 2, time);
		gpuComputeObj.commandQueue.putAcquireGLObject(gpuComputeObj.clGLBuffers.get(VERTICES_NAME).ID)
									.put2DRangeKernel(gpuComputeObj.kernels.get(KERNEL_NAME), 0, 0, 256, 256, 0, 0)
									.putReleaseGLObject(gpuComputeObj.clGLBuffers.get(VERTICES_NAME).ID)
									.finish();
	}
	
	@Override
	public int getVertexObjectId(String buffer) {
		return gpuComputeObj.getVertexObjectId(buffer);
	}
	
	@Override
	public int getArraySize() {
		return MESH_SIZE * MESH_SIZE;
	}
	
	@Override
	public boolean isInitialized() {
		return this.initialized;
	}
	
}
